/**
 * Copyright (c) 2017-2024 Nop Platform. All rights reserved.
 * Author: canonical_entropy@163.com
 * Blog:   https://www.zhihu.com/people/canonical-entropy
 * Gitee:  https://gitee.com/canonical-entropy/nop-entropy
 * Github: https://github.com/entropy-cloud/nop-entropy
 */
package com.gitee.wsl.struct.table.impl

import com.gitee.wsl.ext.string.limitLength
import com.gitee.wsl.struct.compare.diff.text.normalizeHtml
import com.gitee.wsl.struct.table.ICell
import com.gitee.wsl.struct.table.IColumnConfig
import com.gitee.wsl.struct.table.IRow
import com.gitee.wsl.struct.table.ITable
import timber.log.Timber
import kotlin.jvm.JvmOverloads
import kotlin.math.max
import kotlin.math.min

abstract class AbstractTable<T : IRow> : ITable<T> {

    override var isFrozen: Boolean = false

    override var id: String? = null
        set(value) {
            checkAllowChange()
            field = value
        }
    override var styleId: String? = null

    override var colCount = -1

    override var headerCount: Int = 0
        set(headerCount) {
            checkAllowChange()
            field = headerCount
        }

    override var sideCount: Int = 0
        set(sideCount) {
            checkAllowChange()
            field = sideCount
        }

    override var footerCount: Int = 0
        set(footerCount) {
            checkAllowChange()
            field = footerCount
        }

    override fun toString(): String {
        return "Table[id=" + id + ",rowCount=" + rows.size + ",colCount=" + this.colCount + "]"
    }

    abstract override val cols: List<IColumnConfig>

    override fun freeze(cascade: Boolean) {
        if (cascade) {
            for (row in rows) {
                row.freeze(true)
            }
        }
    }

    override val rowCount: Int
        get() = rows.size

    fun colCount(): Int {
        if (colCount < 0) {
            var max = 0
            for (row in rows) {
                max = max(max, row.colCount)
            }
            colCount = max
        }
        return colCount
    }

    abstract override val rows: MutableList<T>

    override fun getRow(rowIndex: Int): T? {
        val rows: List<T> = rows
        if (rowIndex < 0 || rowIndex >= rows.size) return null
        return rows[rowIndex]
    }

    override fun makeRow(rowIndex: Int): T {
        val rows = rows
        for (i in rows.size..rowIndex) {
            checkAllowChange()
            val row = newRow()
            row.table = this
            rows.add(row)
        }
        return rows[rowIndex]
    }

    override fun insertRow(rowIndex: Int) {
        insertRows(rowIndex, 1, null)
    }

    override fun insertRows(rowIndex: Int, count: Int, extendCols: IntArray?) {
        checkAllowChange()
        val rows = rows
        if (rowIndex >= rows.size) {
            for (i in rows.size until rowIndex + count) {
                val row = newRow()
                row.table = this
                rows.add(row)
            }
            if (extendCols == null) return
        } else {
            for (i in 0 until count) {
                val row = newRow()
                row.table = this
                rows.add(rowIndex, row)
            }
        }

        if (rowIndex > 0) {
            _expandProxy(rowIndex, count, extendCols)
        }
    }

    // 新增行导致合并单元格被扩展
    private fun _expandProxy(rowIndex: Int, count: Int, extendCols: IntArray?) {
        // 在修改realCell属性之前先延展下方的proxy
        val afterRow: IRow? = getRow(rowIndex + count)
        if (afterRow != null) {
            val cells = afterRow.cells
            var j = 0
            val m = cells.size
            while (j < m) {
                val icell: ICell? = cells[j]
                if (icell == null) {
                    j++
                    continue
                }

                val cell: ICell = icell.realCell
                // 上方延展下来的
                if (icell.rowOffset > 0) {
                    // 下方的proxy单元格的rowOffset+count
                    val startRow = rowIndex + count
                    val lastRow: Int = startRow + cell.mergeDown - icell.rowOffset

                    for (p in startRow..lastRow) {
                        for (k in 0..cell.mergeAcross) {
                            val proxy: ICell = getProxy(p, j + k)
                            proxy.rowOffset += count
                        }
                    }
                }
                j += cell.mergeAcross
                j++
            }
        }

        // 如果前面的行要向下延展，则在插入的空行中补充proxy
        val beforeRow: IRow? = getRow(rowIndex - 1)
        if (beforeRow != null) {
            val cells: List<ICell?> = beforeRow.cells
            var j = 0
            val m = cells.size
            while (j < m) {
                val icell = cells[j]
                if (icell == null) {
                    j++
                    continue
                }

                val cell: ICell = icell.realCell

                // 如果指定延展或者跨越了插入行
                if (extendCols!!.indexOf(j) >= 0 || cell.mergeDown > icell.rowOffset) {
                    cell.mergeDown += count

                    for (i in 0 until count) {
                        for (k in 0..cell.mergeAcross) {
                            val proxy: ICell = newProxyCell(cell, icell.rowOffset + i + 1, k)
                            getRow(rowIndex + i)?.internalSetCell(j + k, proxy)
                        }
                    }
                }
                j += cell.mergeAcross
                j++
            }
        }
    }

    override fun removeRow(rowIndex: Int) {
        removeRows(rowIndex, 1)
    }

    override fun removeRows(rowIndex: Int, count: Int) {
        var count = count
        checkAllowChange()
        if (rowIndex >= rows.size) return
        if (rowIndex + count > rows.size) {
            count = rows.size - rowIndex
        }
        _removeProxy(rowIndex, count)
        for (i in 0 until count) {
            rows.removeAt(rowIndex)
        }
        this.invalidateColCount()
    }

    fun _removeProxy(rowIndex: Int, count: Int) {
        var row :IRow? = getRow(rowIndex)?:return
        var cells = row!!.cells
        var j = 0
        val m = cells.size
        while (j < m) {
            val icell = cells[j]
            if (icell == null) {
                j++
                continue
            }
            val cell: ICell = icell.realCell
            if (icell.isProxyCell) {
                // 贯穿
                if (cell.mergeDown - icell.rowOffset >= count) { //NOPMD - suppressed EmptyControlStatement
                    // 后面再处理
                    // ignore
                } else {
                    cell.mergeDown = icell.rowOffset - 1
                }
            }
            j += cell.mergeAcross
            j++
        }

        row = getRow(rowIndex + count)
        if (row != null) {
            cells = row.cells
            var j = 0
            val m = cells.size
            while (j < m) {
                val icell = cells[j]
                if (icell == null) {
                    j++
                    continue
                }

                val cell: ICell = icell.realCell
                // 上方延展下来的。 rowOffset>0必然是proxy
                if (icell.rowOffset > 0) {
                    val rowOffset: Int = icell.rowOffset
                    val start = rowIndex + count - rowOffset

                    if (rowOffset > count) {
                        // 贯穿下来的单元格
                        var p = rowOffset
                        val n: Int = cell.mergeDown
                        while (p <= n) {
                            for (k in 0..cell.mergeAcross) {
                                val proxy: ICell = getProxy(start + p, j + k)
                                proxy.rowOffset = p - count
                            }
                            p++
                        }
                        cell.mergeDown -= count

                    } else {
                        // RealCell在被删除的区间内
                        this.doRemoveCell(icell, rowIndex + count, j)
                    }
                }
                j += cell.mergeAcross
                j++
            }
        }
    }

    private fun invalidateColCount() {
        colCount = -1
    }

    fun validate() {
        val rows: List<T> = rows
        var i = 0
        val n = rows.size
        while (i < n) {
            val row: IRow = rows[i]
            val cols: Int = row.colCount
            var j = 0
            while (j < cols) {
                val cell = row.getCell(j)
                if (cell == null) {
                    j++
                    continue
                }
                if (cell.isProxyCell) {
                    validateProxy(cell, i, j)
                } else {
                    validateRealCell(cell, i, j)
                }
                j += cell.realCell.mergeAcross
                j++
            }
            i++
        }
    }

    fun validateProxy(cell: ICell, rowIndex: Int, colIndex: Int) {
        val realCell: ICell? =
            getCell(rowIndex - cell.rowOffset, colIndex - cell.colOffset)
        if (realCell !== cell.realCell)
            throw IllegalArgumentException("ERR_TABLE_INVALID_PROXY_CELL")
                /*.param(
            ARG_CELL,
            cell
        ).param(ARG_ROW_INDEX, rowIndex)
            .param(ARG_COL_INDEX, colIndex)*/
    }

    fun validateRealCell(cell: ICell, rowIndex: Int, colIndex: Int) {
        for (i in 0..cell.mergeDown) {
            for (j in 0..cell.mergeAcross) {
                if (i == 0 && j == 0) continue
                val proxy: ICell? = getCell(rowIndex + i, colIndex + j)
                if (proxy == null || !proxy.isProxyCell)
                    throw IllegalArgumentException("ERR_TABLE_NOT_PROXY_CELL")
                       /* .param(ARG_ROW_INDEX, rowIndex + i)
                    .param(ARG_COL_INDEX, colIndex + j)*/

                if (proxy.rowOffset != i || proxy.colOffset != j)
                    throw IllegalArgumentException("ERR_TABLE_INVALID_PROXY_CELL")
                       /* .param(ARG_CELL, proxy)
                    .param(ARG_ROW_INDEX, rowIndex + i).param(ARG_COL_INDEX, rowIndex + j)*/
            }
        }
    }

    override fun insertCol(colIndex: Int) {
        insertCols(colIndex, 1, null)
    }

    override fun insertCols(colIndex: Int, count: Int, extendRows: IntArray?) {
        checkAllowChange()
        invalidateColCount()
        _insertCols(colIndex, count)

        if (colIndex == 0) return

        val rows: List<T> = rows
        run {
            var i = 0
            val n = rows.size
            while (i < n) {
                val row: IRow = rows[i]

                val icell= row.getCell(colIndex + count)
                if (icell == null) {
                    i++
                    continue
                }

                val cell: ICell = icell.realCell
                if (icell.colOffset > 0) {
                    val colOffset: Int = icell.colOffset
                    val start = colIndex + count - colOffset
                    for (p in 0..cell.mergeDown) {
                        for (k in colOffset..cell.mergeAcross) {
                            val proxy: ICell = getProxy(i + p, start + k)
                            proxy.colOffset = k + count
                        }
                    }
                }
                i += cell.mergeDown
                i++
            }
        }

        var i = 0
        val n = rows.size
        while (i < n) {
            val row: IRow = rows[i]

            val icell= row.getCell(colIndex - 1)
            if (icell == null) {
                i++
                continue
            }

            val cell: ICell = icell.realCell
            if (extendRows!!.indexOf( i) >= 0 || cell.mergeAcross > icell.colOffset) {
                cell.mergeAcross += count
                val colOffset: Int = icell.colOffset
                for (p in 0..cell.mergeDown) {
                    val row2: IRow? = getRow(i + p)
                    for (k in 0 until count) {
                        val proxy: ICell = newProxyCell(cell, p, colOffset + k + 1)
                        row2?.internalSetCell(colIndex + k, proxy)
                    }
                }
            }
            i += cell.mergeDown
            i++
        }
    }

    private fun _insertCols(colIndex: Int, count: Int) {
        val rows: List<T> = rows
        var i = 0
        val n = rows.size
        while (i < n) {
            val row: IRow = rows[i]
            val cols: Int = row.colCount
            // 如果行的列数较少，则直接跳过，没必要添加，setCell时会自动增加列
            if (colIndex >= cols) {
                i++
                continue
            }

            for (k in 0 until count) {
                row.internalInsertCell(colIndex, null)
            }
            i++
        }
    }

    override fun removeCol(colIndex: Int) {
        removeCols(colIndex, 1)
    }

    override fun removeCols(colIndex: Int, count: Int) {
        var count = count
        checkAllowChange()
        if (colIndex >= colCount) return

        if (colIndex + count > colCount) {
            count = colCount - colIndex
        }

        invalidateColCount()

        val rows: List<T> = rows
        run {
            var i = 0
            val n = rows.size
            while (i < n) {
                val row: IRow = rows[i]

                val icell = row.getCell(colIndex)
                if (icell == null) {
                    i++
                    continue
                }

                val cell: ICell = icell.realCell
                if (icell.isProxyCell) {
                    // 贯穿
                    if (cell.mergeAcross - icell.colOffset >= count) { //NOPMD - suppressed EmptyControlStatement
                        // 后面再处理
                        // ignore
                    } else {
                        cell.mergeAcross = icell.colOffset - 1
                    }
                }
                i += cell.mergeDown
                i++
            }
        }

        var i = 0
        val n = rows.size
        while (i < n) {
            val row: IRow = rows[i]

            val icell = row.getCell(colIndex + count)
            if (icell == null) {
                i++
                continue
            }

            val cell: ICell = icell.realCell
            // 左方延展过来的
            if (icell.colOffset > 0) {
                val colOffset: Int = icell.colOffset
                if (colOffset > count) {
                    val start = colIndex + count - colOffset
                    var p = colOffset
                    val m: Int = cell.mergeAcross
                    while (p <= m) {
                        for (k in 0..cell.mergeDown) {
                            val proxy: ICell = getProxy(i + k, start + p)
                            proxy.colOffset = p - count
                        }
                        p++
                    }
                    cell.mergeAcross -= count
                } else {
                    // RealCell在被删除的区间中
                    doRemoveCell(icell, i, colIndex + count)
                }
            }
            i += cell.mergeDown
            i++
        }

        _deleteCols(colIndex, count)
    }

    private fun _deleteCols(colIndex: Int, count: Int) {
        val rows: List<T> = rows
        var i = 0
        val n = this.rowCount
        while (i < n) {
            val row: IRow = rows[i]
            val cols: Int = row.colCount
            if (cols <= colIndex) {
                i++
                continue
            }

            val m = min(cols.toDouble(), (colIndex + count).toDouble()).toInt()
            for (j in m - 1 downTo colIndex) {
                row.internalRemoveCell(j)
            }
            i++
        }
    }

    fun getProxy(rowIndex: Int, colIndex: Int): ICell {
        val cell = getCell(rowIndex, colIndex)
        if (cell == null || !cell.isProxyCell) 
            throw IllegalArgumentException("ERR_TABLE_NOT_PROXY_CELL")
            /*.param(
            ARG_ROW_INDEX,
            rowIndex
        ).param(
            ARG_COL_INDEX,
            colIndex
        )*/
        return cell
    }

    override fun getCell(rowIndex: Int, colIndex: Int): ICell? {
        val row: T = getRow(rowIndex) ?: return null
        return row.getCell(colIndex)
    }

    override fun makeCell(rowIndex: Int, colIndex: Int): ICell? {
        val row: IRow = makeRow(rowIndex)
        return row.makeCell(colIndex)
    }

    override fun setCell(rowIndex: Int, colIndex: Int, cell: ICell?) {
        checkAllowChange()
        if(cell!=null){
            if (colCount >= 0 && colIndex + cell.mergeAcross >= colCount)
                invalidateColCount()
        }

        if (cell == null) {
            internalSetCell(makeRow(rowIndex), rowIndex, colIndex, null)
            return
        }

        require(!cell.isProxyCell) { "only RealCell is allowed" }
        
        doSetCell(makeRow(rowIndex), rowIndex, colIndex, cell)
    }

    fun doSetCell(row: IRow, rowIndex: Int, colIndex: Int, cell: ICell) {
        internalSetCell(row, rowIndex, colIndex, cell)

        val mergeAcross: Int = cell.mergeAcross
        val mergeDown: Int = cell.mergeDown

        if (mergeAcross > 0) {
            for (i in 1..mergeAcross) {
                val proxyCell: ICell = newProxyCell(cell, 0, i)
                cell.row = row
                internalSetCell(row, rowIndex, colIndex + i, proxyCell)
            }
        }
        if (mergeDown > 0) {
            for (i in 1..mergeDown) {
                val nextRow: IRow = makeRow(rowIndex + i)
                for (j in 0..mergeAcross) {
                    val proxyCell: ICell = newProxyCell(cell, i, j)
                    internalSetCell(nextRow, rowIndex + i, colIndex + j, proxyCell)
                }
            }
        }
    }

    fun internalSetCell(row: IRow, rowIndex: Int, colIndex: Int, cell: ICell?) {
        val oldCell = row.getCell(colIndex)
        if (oldCell === cell) return

        if (oldCell != null) {
            this.doRemoveCell(oldCell, rowIndex, colIndex)
        }
        row.internalSetCell(colIndex, cell)
    }

    fun doRemoveCell(cell: ICell, rowIndex: Int, colIndex: Int) {
        var cell: ICell = cell
        var rowIndex = rowIndex
        var colIndex = colIndex
        if (cell.isProxyCell) {
            rowIndex -= cell.rowOffset
            colIndex -= cell.colOffset
            cell = cell.realCell
        }

        var i = 0
        val n: Int = cell.mergeDown
        while (i <= n) {
            var j = 0
            val m: Int = cell.mergeAcross
            while (j <= m) {
                getRow(i + rowIndex)?.internalSetCell(j + colIndex, null)
                j++
            }
            i++
        }
    }

    override fun mergeCell(rowIndex: Int, colIndex: Int, mergeDown: Int, mergeAcross: Int) {
        checkAllowChange()
        val cell = this.makeCell(rowIndex, colIndex)?:return
        if (cell.isProxyCell) 
            throw IllegalArgumentException("ERR_TABLE_MERGE_CELL_EMPTY_OR_PROXY_CELL")
            /*.param(ARG_CELL, cell)
            .param(ARG_ROW_INDEX, rowIndex).param(ARG_COL_INDEX, colIndex)*/

        this.invalidateColCount()

        val curMergeDown: Int = cell.mergeDown
        val curMergeAcross: Int = cell.mergeAcross

        val minDown = min(curMergeDown, mergeDown)
        val minAcross = min(curMergeAcross, mergeAcross)

        // 原先的合并范围较大，需要缩减
        if (curMergeAcross > mergeAcross || curMergeDown > mergeDown) {
            for (i in minDown..curMergeDown) {
                for (j in minAcross..curMergeAcross) {
                    if (i == 0 && j == 0) continue
                    if (i > mergeDown || j > mergeAcross) makeRow(rowIndex + i).internalSetCell(
                        colIndex + j,
                        null
                    )
                }
            }
        }

        cell.mergeAcross = mergeAcross
        cell.mergeDown = mergeDown

        if (curMergeAcross < mergeAcross || curMergeDown < mergeDown) {
            for (i in minDown..mergeDown) {
                for (j in minAcross..mergeAcross) {
                    // 后续判断自动跳过此情况
                    // if (i == 0 && j == 0)
                    // continue;
                    if (i <= curMergeDown && j <= curMergeAcross) continue

                    val row: IRow = makeRow(rowIndex + i)
                    val proxy: ICell = newProxyCell(cell, i, j)
                    internalSetCell(row, rowIndex + i, colIndex + j, proxy)
                }
            }
        }
    }

    override fun <V:ICell> addToRow(rowIndex: Int, cell: V) {
        checkAllowChange()
        if (cell.isProxyCell) {
            throw IllegalArgumentException("only RealCell is allowed")
        }

        invalidateColCount()

        val row: IRow = makeRow(rowIndex)
        var i = 0
        val cols: Int = row.colCount
        while (i < cols) {
            val c: ICell = row.getCell(i) ?: break
            i++
        }

        if (!_isSpaceAvailable(
                row,
                rowIndex,
                i,
                cell.mergeDown,
                cell.mergeAcross
            )
        ) 
            throw IllegalArgumentException("ERR_TABLE_NO_ENOUGH_FREE_SPACE")
               /* .param(ARG_ROW_INDEX, rowIndex)
            .param(ARG_COL_INDEX, i).param(ARG_MERGE_DOWN, cell.mergeDown)
            .param(ARG_MERGE_ACROSS, cell.mergeAcross)*/
        doSetCell(row, rowIndex, i, cell)
    }

    override fun isSpaceAvailable(rowIndex: Int, colIndex: Int, mergeDown: Int, mergeAcross: Int): Boolean {
        val row: T = getRow(rowIndex) ?: return true
        return _isSpaceAvailable(row, rowIndex, colIndex, mergeDown, mergeAcross)
    }

    private fun _isSpaceAvailable(
        row: IRow,
        rowIndex: Int,
        colIndex: Int,
        mergeDown: Int,
        mergeAcross: Int
    ): Boolean {
        if (row.getCell(colIndex) != null) return false

        if (mergeAcross > 0) {
            for (i in 1..mergeAcross) {
                if (row.getCell(colIndex + i) != null) return false
            }
        }
        if (mergeDown > 0) {
            for (i in 1..mergeDown) {
                val nextRow: T = getRow(rowIndex + 1 + i) ?: break
                for (j in 0..mergeAcross) {
                    if (nextRow.getCell(colIndex + j) != null) return false
                }
            }
        }
        return true
    }

    override fun rbind(table: ITable<T>) {
        checkAllowChange()
        val colCount = this.colCount
        val rowCount = rowCount
        val newColCount: Int = table.colCount
        val newRowCount: Int = table.rowCount
        var i = 0
        val n = newRowCount
        while (i < n) {
            val row: IRow = this.makeRow(rowCount + i)
            val brow = table.getRow(i)
            var j = 0
            val m = brow?.colCount?:0
            while (j < m) {
                val cell = brow?.getCell(j)
                if (cell != null && !cell.isProxyCell) {
                    doSetCell(row, rowCount + i, j, cell.cloneInstance())
                }
                j++
            }
            i++
        }
        this.colCount = max(colCount, newColCount)
    }

    override fun cbind(table: ITable<T>) {
        checkAllowChange()
        val colCount = this.colCount
        val rowCount: Int = table.rowCount
        var i = 0
        val n = rowCount
        while (i < n) {
            val row = this.makeRow(i)
            val brow = table.getRow(i)!!
            var j = 0
            val m: Int = brow.colCount
            while (j < m) {
                val cell = brow.getCell(j)
                if (cell != null && !cell.isProxyCell) {
                    doSetCell(row, i, colCount + j, cell.cloneInstance())
                }
                j++
            }
            i++
        }
        this.colCount = colCount + table.colCount
    }

    override fun trimTable(maxRowCount: Int, maxColCount: Int) {
        checkAllowChange()
        if (colCount >= 0) {
            if (colCount <= maxColCount && rowCount <= maxRowCount) return
        }

        val rows = rows
        if (maxRowCount <= 0) {
            this.invalidateColCount()
            rows.clear()
            return
        }

        if (maxColCount <= 0) {
            this.invalidateColCount()
            rows.clear()
            return
        }

        if (rows.size > maxRowCount) {
            removeRows(maxRowCount, rows.size - maxRowCount)
        }
        if (colCount > maxColCount) {
            removeCols(maxColCount, colCount - maxColCount)
        }
    }

    override fun trimBlankCols() {
        val rowCount = rowCount
        var colCount = colCount

        while (colCount > 0) {
            if (!isAllColumnCellSatisfy(colCount - 1) { cell -> cell == null || cell.isBlankCell }) break
            colCount--
        }
        trimTable(rowCount, colCount)
    }

    override fun trimBlankRows() {
        checkAllowChange()
        val rowCount = rowCount

        // int colCount = colCount;
        for (rowIndex in rowCount - 1 downTo 0) {
            if (!isAllRowCellSatisfy(rowIndex) { cell -> cell?.isBlankCell == true }) break
            rows.removeAt(rowIndex)
        }
    }

    @JvmOverloads
    fun dump(title: String? = "table.dump") {
        Timber.i("{}:\n{}", title, toDebugString())
    }

    /*fun toHtmlString(): String {
        return HtmlTableOutput.toHtml(this)
    }*/

    fun toDebugString(): String {
        val sb = StringBuilder()
        val rowCount = this.rowCount
        for (rowIndex in 0 until rowCount) {
            val row: IRow = getRow(rowIndex)?:continue
            sb.append((rowIndex + 1).toString().padStart(2,' '))
            sb.append(':')

            run {
                var colIndex = 0
                val colCount: Int = row.colCount
                while (colIndex < colCount) {
                    val cell= row.getCell(colIndex)
                    if (colIndex != 0) sb.append('|')

                    val pos: Int = sb.length
                    if (cell == null) {
                        sb.append("   null")
                    } else if (cell.isProxyCell) {
                        sb.append("   {+").append(cell.rowOffset).append(",+")
                            .append(cell.colOffset).append('}')
                    } else {
                        sb.append('[').append(colIndex).append("]")
                        if (cell.mergeDown > 0 || cell.mergeAcross > 0) {
                            sb.append("{").append(cell.rowSpan).append(",")
                                .append(cell.colSpan).append("}")
                        }
                        val text: String = normalizeText(cell.text).limitLength(10)
                        sb.append(text)
                    }
                    var pos2: Int = sb.length
                    // 增加padding
                    while (pos2 < pos + 15) {
                        sb.append(' ')
                        pos2++
                    }
                    colIndex++
                }
            }
            sb.append('\n')
        }
        return sb.toString()
    }

    fun normalizeText(text: String): String {
        return text.normalizeHtml()
        //return StringHelper.replaceChars(text, "\t\r\n", "   ")
    }

    protected abstract fun newRow(): T

    fun addRow(row: T) {
        checkAllowChange()
        row.table = this
        rows.add(row)
    }

    /*protected fun outputJson(handler: IJsonHandler) {
        if (id != null) handler.put("id", id)
        if (styleId != null) handler.put("styleId", styleId)
        //
//        List<? extends IColumnConfig> cols = getCols();
//        if (cols != null && cols.size() > 0) {
//            handler.put("cols", cols);
//        }
//        handler.put("rows", getRows());
        super.outputJson(handler)
    }*/

    fun normalizeMergeRanges() {
        val rowCount = rowCount
        val colCount = colCount

        for (i in 0 until rowCount) {
            val row: IRow? = getRow(i)
            for (j in 0 until colCount) {
                val cell = row?.getCell(j)
                if (cell != null && !cell.isProxyCell) {
                    if (cell.mergeAcross > 0 || cell.mergeDown > 0) {
                        this.setCell(i, j, cell)
                    }
                }
            }
        }
    }


}